package ru.artyushov.fingers.core.preprocessor;

import ru.artyushov.fingers.core.Preprocessor;
import ru.artyushov.fingers.core.basic.SpecialPointsExtractor;
import ru.artyushov.fingers.core.basic.SpecialPointsFeatureSet;
import ru.artyushov.fingers.core.data.Fingerprint;
import ru.artyushov.fingers.core.data.Point;

import java.util.Collection;

public class SpuriousForkRemover implements Preprocessor {

    private final int threshold;

    public SpuriousForkRemover(int threshold) {
        this.threshold = threshold;
    }

    @Override
    public Fingerprint workYourMagic(Fingerprint on) {
        final SpecialPointsFeatureSet specialPointsFeatureSet = new SpecialPointsExtractor().extractFeatures(on);
        final Collection<Point> forks = specialPointsFeatureSet.getForks();

        final boolean[][] data = on.getData();

        for(Point fork : forks) {
            removeSpuriousForks(data, fork, new boolean[on.getColNumber()][on.getRowNumber()], on.getColNumber(), on.getRowNumber(), 0);
        }

        return new Fingerprint(data, on.getRowNumber());
    }

    private boolean removeSpuriousForks(boolean[][] data, Point fork, boolean[][] visited, int cols, int rows, int depth) {

        visited[fork.x][fork.y] = true;

        if(depth >= threshold) {
            //means that the path was long enough, this branch was not spurious
            return true;
        } else {

            //at least one of branches from this point is long enough
            boolean iShouldBeSaved = false;

            for(int i = -1; i <= 1; i ++) {
                for(int j = -1; j <= 1; j ++) {

                    if(i == 0 && j == 0) continue;

                    int newX = fork.x + i;
                    int newY = fork.y + j;

                    if(newX >= 0 && newY >= 0 && newX < cols && newY < rows) {
                        if(data[newX][newY] && !visited[newX][newY]) {
                            boolean subPathIsLong = removeSpuriousForks(data, new Point(newX, newY), visited, cols, rows, depth + 1);

                            if(subPathIsLong) {
                                iShouldBeSaved = true;
                            }
                        }
                    }
                }
            }

            if(!iShouldBeSaved) {
                data[fork.x][fork.y] = false;
            }

            return iShouldBeSaved;

        }
    }
}
